﻿using System;
using System.Linq;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Media;

namespace Common.UI.Helper
{
    public static class VisualHelper
    {
        internal static VisualStateGroup TryGetVisualStateGroup(DependencyObject d, string groupName)
        {
            FrameworkElement implementationRoot = GetImplementationRoot(d);
            if (implementationRoot == null)
            {
                return null;
            }
            return VisualStateManager.GetVisualStateGroups(implementationRoot)?.OfType<VisualStateGroup>().FirstOrDefault((VisualStateGroup group) => string.CompareOrdinal(groupName, group.Name) == 0);
        }

        internal static FrameworkElement GetImplementationRoot(DependencyObject d)
        {
            if (1 != VisualTreeHelper.GetChildrenCount(d))
            {
                return null;
            }
            return VisualTreeHelper.GetChild(d, 0) as FrameworkElement;
        }

        public static T GetChild<T>(DependencyObject d) where T : DependencyObject
        {
            if (d == null)
            {
                return null;
            }
            if (d is T result)
            {
                return result;
            }
            int childrenCount = VisualTreeHelper.GetChildrenCount(d);
            if (childrenCount > 0)
            {
                for (int i = 0; i < childrenCount; i++)
                {
                    T child = GetChild<T>(VisualTreeHelper.GetChild(d, i));
                    if (child != null)
                    {
                        return child;
                    }
                }
            }
            return null;
        }

        public static T GetVisualChild<T>(DependencyObject parent, Func<T, bool> predicate) where T : Visual
        {
            int childrenCount = VisualTreeHelper.GetChildrenCount(parent);
            for (int i = 0; i < childrenCount; i++)
            {
                DependencyObject child = VisualTreeHelper.GetChild(parent, i);
                if (!(child is T val))
                {
                    T visualChild = GetVisualChild(child, predicate);
                    if (visualChild != null)
                    {
                        return visualChild;
                    }
                }
                else if (predicate(val))
                {
                    return val;
                }
            }
            return null;
        }

        public static IntPtr GetHandle(this Visual visual)
        {
            return (PresentationSource.FromVisual(visual) as HwndSource)?.Handle ?? IntPtr.Zero;
        }

        internal static void HitTestVisibleElements(Visual visual, HitTestResultCallback resultCallback, HitTestParameters parameters)
        {
            VisualTreeHelper.HitTest(visual, ExcludeNonVisualElements, resultCallback, parameters);
        }

        private static HitTestFilterBehavior ExcludeNonVisualElements(DependencyObject potentialHitTestTarget)
        {
            if (!(potentialHitTestTarget is Visual))
            {
                return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
            }
            if (!(potentialHitTestTarget is UIElement uIElement) || (uIElement.IsVisible && uIElement.IsEnabled))
            {
                return HitTestFilterBehavior.Continue;
            }
            return HitTestFilterBehavior.ContinueSkipSelfAndChildren;
        }

        internal static bool ModifyStyle(IntPtr hWnd, int styleToRemove, int styleToAdd)
        {
            //int windowLong = InteropMethods.GetWindowLong(hWnd, InteropValues.GWL.STYLE);
            //int num = (windowLong & ~styleToRemove) | styleToAdd;
            //if (num == windowLong)
            //{
            //    return false;
            //}
            //InteropMethods.SetWindowLong(hWnd, InteropValues.GWL.STYLE, num);
            return true;
        }


        internal static bool SetScrollToBottom2(UIElement uIElement)
        {
            //int windowLong = InteropMethods.GetWindowLong(hWnd, InteropValues.GWL.STYLE);
            //int num = (windowLong & ~styleToRemove) | styleToAdd;
            //if (num == windowLong)
            //{
            //    return false;
            //}
            //InteropMethods.SetWindowLong(hWnd, InteropValues.GWL.STYLE, num);
            return true;
        }
    }

}
